package 文本搜索替换;

import org.apache.commons.io.input.BOMInputStream;

import javax.swing.*;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.*;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

public class textReplacement extends JFrame {
    private JTextArea textArea;
    private JTextField filePathField,searchField,replaceField;
    private ArrayList<Integer> matchPosion = new ArrayList<>();
    private Highlighter.HighlightPainter highlightPainter;
    private int currentMatchIndex=-1;
    public textReplacement(){
        setTitle("文本替换工具");
        setSize(600,400);
        highlightPainter= new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);
        init();
    }

    public void init() {
        //文件路径区域
        JPanel filePath = new JPanel(new BorderLayout());
        filePathField=new JTextField();
        JButton openBtn=new JButton("打开");
        openBtn.addActionListener(this::openFile);
        filePath.add(filePathField,BorderLayout.CENTER);
        filePath.add(openBtn,BorderLayout.EAST);

        //文本展示区域
        textArea=new JTextArea();
        JScrollPane jScrollPane=new JScrollPane(textArea);
        //搜索操作区域
        JPanel searchPanel = new JPanel(new GridLayout(2, 1));
        searchPanel.setBackground(Color.black);
        //查找区域
        JPanel searchRow=new JPanel(new BorderLayout());
        searchField=new JTextField();
        JButton SearchBtn = new JButton("查找");
        SearchBtn.addActionListener(this::highlightMatched);
        searchRow.add(searchField,BorderLayout.CENTER);
        searchRow.add(SearchBtn,BorderLayout.EAST);

        //替换区域
        JPanel replaceRow=new JPanel(new BorderLayout());
        replaceField=new JTextField();
        JButton replaceBtn=new JButton("替换");
        replaceBtn.addActionListener(this::replaceText);
        replaceRow.add(replaceField,BorderLayout.CENTER);
        replaceRow.add(replaceBtn,BorderLayout.EAST);

        searchPanel.add(searchRow);
        searchPanel.add(replaceRow);
        //上一个下一个
        JPanel preNext=new JPanel(new FlowLayout());
        JButton pre=new JButton("上一个");
        pre.addActionListener(e->navigateMatches(-1));
        JButton next=new JButton("下一个");
        next.addActionListener(e->navigateMatches(1));
        preNext.add(pre);
        preNext.add(next);

        //文本路径顶部，多文本输入框中部，然后下面搜索，替换和pre和next的变成南部再做布局
        setLayout(new BorderLayout());
        add(filePath,BorderLayout.NORTH);
        add(jScrollPane,BorderLayout.CENTER);

        JPanel NorthPanel=new JPanel(new BorderLayout());
        NorthPanel.add(searchPanel,BorderLayout.NORTH);
        NorthPanel.add(preNext,BorderLayout.CENTER);
        add(NorthPanel,BorderLayout.SOUTH);
        setVisible(true);
    }

    private void openFile(ActionEvent e) {
        JFileChooser fc=new JFileChooser();
        if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            File file = fc.getSelectedFile();
            filePathField.setText(file.getAbsolutePath());

            try (InputStream is=new FileInputStream(file);
                BOMInputStream bomIs =new BOMInputStream(is);
                //主要是这个BOMInputStream可以拿到文件的BOM开头，所以直接用这个，然后由于多态，所以可以直接传入BOMInputStream
                Reader reader =new InputStreamReader(
                        bomIs,
                        bomIs.hasBOM() ? bomIs.getBOMCharsetName():"GBK")){
                BufferedReader br=new BufferedReader(reader);
                StringBuilder content = new StringBuilder();
                String Line;
                while ((Line = br.readLine()) != null) {
                    content.append(Line).append("\n");
                }
                textArea.setText(content.toString());
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(this, "文件读取失败");
            }
        }
    }
    private void highlightMatched(ActionEvent e){
        textArea.getHighlighter().removeAllHighlights();
        matchPosion.clear();
        currentMatchIndex=-1;
        String pattern=searchField.getText();
        if(pattern.isEmpty()){return;}
        String text=textArea.getText();
        try{
            Pattern p=Pattern.compile(pattern);
            Matcher matcher=p.matcher(text);
            while(matcher.find()){
                int start=matcher.start();
                int end=matcher.end();
                textArea.getHighlighter().addHighlight(start,end,highlightPainter);
                matchPosion.add(start);
            }
        }catch (PatternSyntaxException ex){
            JOptionPane.showMessageDialog(this,"无效的正则表达式");
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
    private void replaceText(ActionEvent e){
        String search=searchField.getText();
        String replace=replaceField.getText();
        if(replace.isEmpty()){return;}
        try{
            String text=textArea.getText();
            Pattern p=Pattern.compile(search);
            Matcher matcher=p.matcher(text);
            String newText=matcher.replaceAll(replace);
            textArea.setText(newText);
        }catch (PatternSyntaxException ex){
            JOptionPane.showMessageDialog(this,"无效的正则表达式");
        }
    }
    private void navigateMatches(int index){
        if(matchPosion.isEmpty())return;
        currentMatchIndex+=index;
        if(currentMatchIndex<0) currentMatchIndex=matchPosion.size()-1;
        if(currentMatchIndex>=matchPosion.size()) currentMatchIndex=0;
        ScrollMatches(currentMatchIndex);
    }
    private void ScrollMatches(int index){
        int pos=matchPosion.get(index);
        try{
            Rectangle viewRect=textArea.modelToView(pos);
            textArea.scrollRectToVisible(viewRect);
            textArea.setCaretPosition(pos);
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
    public static void main(String[] args) {
        new textReplacement().setVisible(true);
    }
}
